/**
 ******************************************************************************
 * @file    usb_core.c
 * @author  MCD Application Team
 * @version V4.0.0
 * @date    28-August-2012
 * @brief   Standard protocol processing (USB v2.0)
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
 *
 * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *        http://www.st.com/software_license_agreement_liberty_v2
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ValBit(VAR,Place)    (VAR & (1 << Place))
#define SetBit(VAR,Place)    (VAR |= (1 << Place))
#define ClrBit(VAR,Place)    (VAR &= ((1 << Place) ^ 255))
#define Send0LengthData() { _SetEPTxCount(ENDP0, 0); \
    vSetEPTxStatus(EP_TX_VALID); \
  }

#define vSetEPRxStatus(st) (SaveRState = st)
#define vSetEPTxStatus(st) (SaveTState = st)

#define USB_StatusIn() Send0LengthData()
#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID)

#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */
#define StatusInfo1 StatusInfo.bw.bb0

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint16_t_uint8_t StatusInfo;

bool Data_Mul_MaxPacketSize = false;
/* Private function prototypes -----------------------------------------------*/
static void DataStageOut(void);
static void DataStageIn(void);
static void NoData_Setup0(void);
static void Data_Setup0(void);
/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
 * Function Name  : Standard_GetConfiguration.
 * Description    : Return the current configuration variable address.
 * Input          : Length - How many bytes are needed.
 * Output         : None.
 * Return         : Return 1 , if the request is invalid when "Length" is 0.
 *                  Return "Buffer" if the "Length" is not 0.
 *******************************************************************************/
uint8_t *Standard_GetConfiguration(uint16_t Length)
{
    if(Length == 0) {
        pInformation->Ctrl_Info.Usb_wLength =
            sizeof(pInformation->Current_Configuration);
        return 0;
    }
    pUser_Standard_Requests->User_GetConfiguration();
    return (uint8_t *) &pInformation->Current_Configuration;
}

/*******************************************************************************
 * Function Name  : Standard_SetConfiguration.
 * Description    : This routine is called to set the configuration value
 *                  Then each class should configure device itself.
 * Input          : None.
 * Output         : None.
 * Return         : Return USB_SUCCESS, if the request is performed.
 *                  Return USB_UNSUPPORT, if the request is invalid.
 *******************************************************************************/
RESULT Standard_SetConfiguration(void)
{

    if((pInformation->USBwValue0 <= Device_Table.Total_Configuration)
        && (pInformation->USBwValue1 == 0) && (pInformation->USBwIndex == 0)) { /*call Back usb spec 2.0*/
        pInformation->Current_Configuration = pInformation->USBwValue0;
        pUser_Standard_Requests->User_SetConfiguration();
        return USB_SUCCESS;
    }
    else {
        return USB_UNSUPPORT;
    }
}

/*******************************************************************************
 * Function Name  : Standard_GetInterface.
 * Description    : Return the Alternate Setting of the current interface.
 * Input          : Length - How many bytes are needed.
 * Output         : None.
 * Return         : Return 0, if the request is invalid when "Length" is 0.
 *                  Return "Buffer" if the "Length" is not 0.
 *******************************************************************************/
uint8_t *Standard_GetInterface(uint16_t Length)
{
    if(Length == 0) {
        pInformation->Ctrl_Info.Usb_wLength =
            sizeof(pInformation->Current_AlternateSetting);
        return 0;
    }
    pUser_Standard_Requests->User_GetInterface();
    return (uint8_t *) &pInformation->Current_AlternateSetting;
}

/*******************************************************************************
 * Function Name  : Standard_SetInterface.
 * Description    : This routine is called to set the interface.
 *                  Then each class should configure the interface them self.
 * Input          : None.
 * Output         : None.
 * Return         : - Return USB_SUCCESS, if the request is performed.
 *                  - Return USB_UNSUPPORT, if the request is invalid.
 *******************************************************************************/
RESULT Standard_SetInterface(void)
{
    RESULT Re;
    /*Test if the specified Interface and Alternate Setting are supported by
     the application Firmware*/
    Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0,
        pInformation->USBwValue0);

    if(pInformation->Current_Configuration != 0) {
        if((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0)
            || (pInformation->USBwValue1 != 0)) {
            return USB_UNSUPPORT;
        }
        else if(Re == USB_SUCCESS) {
            pUser_Standard_Requests->User_SetInterface();
            pInformation->Current_Interface = pInformation->USBwIndex0;
            pInformation->Current_AlternateSetting = pInformation->USBwValue0;
            return USB_SUCCESS;
        }

    }

    return USB_UNSUPPORT;
}

/*******************************************************************************
 * Function Name  : Standard_GetStatus.
 * Description    : Copy the device request data to "StatusInfo buffer".
 * Input          : - Length - How many bytes are needed.
 * Output         : None.
 * Return         : Return 0, if the request is at end of data block,
 *                  or is invalid when "Length" is 0.
 *******************************************************************************/
uint8_t *Standard_GetStatus(uint16_t Length)
{
    if(Length == 0) {
        pInformation->Ctrl_Info.Usb_wLength = 2;
        return 0;
    }

    /* Reset Status Information */
    StatusInfo.w = 0;

    if(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) {
        /*Get Device Status */
        uint8_t Feature = pInformation->Current_Feature;

        /* Remote Wakeup enabled */
        if(ValBit(Feature, 5)) {
            SetBit(StatusInfo0, 1);
        }
        else {
            ClrBit(StatusInfo0, 1);
        }

        /* Bus-powered */
        if(ValBit(Feature, 6)) {
            SetBit(StatusInfo0, 0);
        }
        else /* Self-powered */
        {
            ClrBit(StatusInfo0, 0);
        }
    }
    /*Interface Status*/
    else if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) {
        return (uint8_t *) &StatusInfo;
    }
    /*Get EndPoint Status*/
    else if(Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) {
        uint8_t Related_Endpoint;
        uint8_t wIndex0 = pInformation->USBwIndex0;

        Related_Endpoint = (wIndex0 & 0x0f);
        if(ValBit(wIndex0, 7)) {
            /* IN endpoint */
            if(_GetTxStallStatus(Related_Endpoint)) {
                SetBit(StatusInfo0, 0); /* IN Endpoint stalled */
            }
        }
        else {
            /* OUT endpoint */
            if(_GetRxStallStatus(Related_Endpoint)) {
                SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */
            }
        }

    }
    else {
        return NULL;
    }
    pUser_Standard_Requests->User_GetStatus();
    return (uint8_t *) &StatusInfo;
}

/*******************************************************************************
 * Function Name  : Standard_ClearFeature.
 * Description    : Clear or disable a specific feature.
 * Input          : None.
 * Output         : None.
 * Return         : - Return USB_SUCCESS, if the request is performed.
 *                  - Return USB_UNSUPPORT, if the request is invalid.
 *******************************************************************************/
RESULT Standard_ClearFeature(void)
{
    uint32_t Type_Rec = Type_Recipient;
    uint32_t Status;

    if(Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) {/*Device Clear Feature*/
        ClrBit(pInformation->Current_Feature, 5);
        return USB_SUCCESS;
    }
    else if(Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) {/*EndPoint Clear Feature*/
        DEVICE* pDev;
        uint32_t Related_Endpoint;
        uint32_t wIndex0;
        uint32_t rEP;

        if((pInformation->USBwValue != ENDPOINT_STALL)
            || (pInformation->USBwIndex1 != 0)) {
            return USB_UNSUPPORT;
        }

        pDev = &Device_Table;
        wIndex0 = pInformation->USBwIndex0;
        rEP = wIndex0 & ~0x80;
        Related_Endpoint = ENDP0 + rEP;

        if(ValBit(pInformation->USBwIndex0, 7)) {
            /*Get Status of endpoint & stall the request if the related_ENdpoint
             is Disabled*/
        Status = _GetEPTxStatus(Related_Endpoint);
    }
    else {
    Status = _GetEPRxStatus(Related_Endpoint);
}

if((rEP >= pDev->Total_Endpoint) || (Status == 0)
    || (pInformation->Current_Configuration == 0)) {
    return USB_UNSUPPORT;
}

if(wIndex0 & 0x80) {
    /* IN endpoint */
    if(_GetTxStallStatus(Related_Endpoint )) {
        ClearDTOG_TX(Related_Endpoint);
        SetEPTxStatus(Related_Endpoint, EP_TX_VALID);
    }
}
else {
    /* OUT endpoint */
    if(_GetRxStallStatus(Related_Endpoint)) {
        if(Related_Endpoint == ENDP0) {
            /* After clear the STALL, enable the default endpoint receiver */
            SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize);
            _SetEPRxStatus(Related_Endpoint, EP_RX_VALID);
        }
        else {
            ClearDTOG_RX(Related_Endpoint);
            _SetEPRxStatus(Related_Endpoint, EP_RX_VALID);
        }
    }
}
pUser_Standard_Requests->User_ClearFeature();
return USB_SUCCESS;
}

return USB_UNSUPPORT;
}

/*******************************************************************************
 * Function Name  : Standard_SetEndPointFeature
 * Description    : Set or enable a specific feature of EndPoint
 * Input          : None.
 * Output         : None.
 * Return         : - Return USB_SUCCESS, if the request is performed.
 *                  - Return USB_UNSUPPORT, if the request is invalid.
 *******************************************************************************/
RESULT Standard_SetEndPointFeature(void)
{
uint32_t wIndex0;
uint32_t Related_Endpoint;
uint32_t rEP;
uint32_t Status;

wIndex0 = pInformation->USBwIndex0;
rEP = wIndex0 & ~0x80;
Related_Endpoint = ENDP0 + rEP;

if(ValBit(pInformation->USBwIndex0, 7)) {
/* get Status of endpoint & stall the request if the related_ENdpoint
 is Disabled*/
Status = _GetEPTxStatus(Related_Endpoint);
}
else {
Status = _GetEPRxStatus(Related_Endpoint);
}

if(Related_Endpoint >= Device_Table.Total_Endpoint
|| pInformation->USBwValue != 0 || Status == 0
|| pInformation->Current_Configuration == 0) {
return USB_UNSUPPORT;
}
else {
if(wIndex0 & 0x80) {
/* IN endpoint */
_SetEPTxStatus(Related_Endpoint, EP_TX_STALL);
}

else {
/* OUT endpoint */
_SetEPRxStatus(Related_Endpoint, EP_RX_STALL);
}
}
pUser_Standard_Requests->User_SetEndPointFeature();
return USB_SUCCESS;
}

/*******************************************************************************
 * Function Name  : Standard_SetDeviceFeature.
 * Description    : Set or enable a specific feature of Device.
 * Input          : None.
 * Output         : None.
 * Return         : - Return USB_SUCCESS, if the request is performed.
 *                  - Return USB_UNSUPPORT, if the request is invalid.
 *******************************************************************************/
RESULT Standard_SetDeviceFeature(void)
{
SetBit(pInformation->Current_Feature, 5);
pUser_Standard_Requests->User_SetDeviceFeature();
return USB_SUCCESS;
}

/*******************************************************************************
 * Function Name  : Standard_GetDescriptorData.
 * Description    : Standard_GetDescriptorData is used for descriptors transfer.
 *                : This routine is used for the descriptors resident in Flash
 *                  or RAM
 *                  pDesc can be in either Flash or RAM
 *                  The purpose of this routine is to have a versatile way to
 *                  response descriptors request. It allows user to generate
 *                  certain descriptors with software or read descriptors from
 *                  external storage part by part.
 * Input          : - Length - Length of the data in this transfer.
 *                  - pDesc - A pointer points to descriptor struct.
 *                  The structure gives the initial address of the descriptor and
 *                  its original size.
 * Output         : None.
 * Return         : Address of a part of the descriptor pointed by the Usb_
 *                  wOffset The buffer pointed by this address contains at least
 *                  Length bytes.
 *******************************************************************************/
uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc)
{
uint32_t wOffset;

wOffset = pInformation->Ctrl_Info.Usb_wOffset;
if(Length == 0) {
pInformation->Ctrl_Info.Usb_wLength = pDesc->Descriptor_Size - wOffset;
return 0;
}

return pDesc->Descriptor + wOffset;
}

/*******************************************************************************
 * Function Name  : DataStageOut.
 * Description    : Data stage of a Control Write Transfer.
 * Input          : None.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void DataStageOut(void)
{
ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;
uint32_t save_rLength;

save_rLength = pEPinfo->Usb_rLength;

if(pEPinfo->CopyData && save_rLength) {
uint8_t *Buffer;
uint32_t Length;

Length = pEPinfo->PacketSize;
if(Length > save_rLength) {
Length = save_rLength;
}

Buffer = (*pEPinfo->CopyData)(Length);
pEPinfo->Usb_rLength -= Length;
pEPinfo->Usb_rOffset += Length;
PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length);

}

if(pEPinfo->Usb_rLength != 0) {
vSetEPRxStatus(EP_RX_VALID);/* re-enable for next data reception */
SetEPTxCount(ENDP0, 0);
vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */
}
/* Set the next State*/
if(pEPinfo->Usb_rLength >= pEPinfo->PacketSize) {
pInformation->ControlState = OUT_DATA;
}
else {
if(pEPinfo->Usb_rLength > 0) {
pInformation->ControlState = LAST_OUT_DATA;
}
else if(pEPinfo->Usb_rLength == 0) {
pInformation->ControlState = WAIT_STATUS_IN;
USB_StatusIn()
;
}
}
}

/*******************************************************************************
 * Function Name  : DataStageIn.
 * Description    : Data stage of a Control Read Transfer.
 * Input          : None.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void DataStageIn(void)
{
ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;
uint32_t save_wLength = pEPinfo->Usb_wLength;
uint32_t ControlState = pInformation->ControlState;

uint8_t *DataBuffer;
uint32_t Length;

if((save_wLength == 0) && (ControlState == LAST_IN_DATA)) {
if(Data_Mul_MaxPacketSize == true) {
/* No more data to send and empty packet */
Send0LengthData()
;
ControlState = LAST_IN_DATA;
Data_Mul_MaxPacketSize = false;
}
else {
/* No more data to send so STALL the TX Status*/
ControlState = WAIT_STATUS_OUT;
vSetEPTxStatus(EP_TX_STALL);

}

goto Expect_Status_Out;
}

Length = pEPinfo->PacketSize;
ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA;

if(Length > save_wLength) {
Length = save_wLength;
}

DataBuffer = (*pEPinfo->CopyData)(Length);

UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);

SetEPTxCount(ENDP0, Length);

pEPinfo->Usb_wLength -= Length;
pEPinfo->Usb_wOffset += Length;
vSetEPTxStatus(EP_TX_VALID);

USB_StatusOut();/* Expect the host to abort the data IN stage */

Expect_Status_Out: pInformation->ControlState = ControlState;
}

/*******************************************************************************
 * Function Name  : NoData_Setup0.
 * Description    : Proceed the processing of setup request without data stage.
 * Input          : None.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void NoData_Setup0(void)
{
RESULT Result = USB_UNSUPPORT;
uint32_t RequestNo = pInformation->USBbRequest;
uint32_t ControlState;

if(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) {
/* Device Request*/
/* SET_CONFIGURATION*/
if(RequestNo == SET_CONFIGURATION) {
Result = Standard_SetConfiguration();
}

/*SET ADDRESS*/
else if(RequestNo == SET_ADDRESS) {
if((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0)
|| (pInformation->USBwIndex != 0)
|| (pInformation->Current_Configuration != 0))
/* Device Address should be 127 or less*/
{
ControlState = STALLED;
goto exit_NoData_Setup0;
}
else {
Result = USB_SUCCESS;
}
}
/*SET FEATURE for Device*/
else if(RequestNo == SET_FEATURE) {
if((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP)
&& (pInformation->USBwIndex == 0)) {
Result = Standard_SetDeviceFeature();
}
else {
Result = USB_UNSUPPORT;
}
}
/*Clear FEATURE for Device */
else if(RequestNo == CLEAR_FEATURE) {
if(pInformation->USBwValue0
== DEVICE_REMOTE_WAKEUP&& pInformation->USBwIndex == 0
&& ValBit(pInformation->Current_Feature, 5)) {
Result = Standard_ClearFeature();
}
else {
Result = USB_UNSUPPORT;
}
}

}

/* Interface Request*/
else if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) {
/*SET INTERFACE*/
if(RequestNo == SET_INTERFACE) {
Result = Standard_SetInterface();
}
}

/* EndPoint Request*/
else if(Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) {
/*CLEAR FEATURE for EndPoint*/
if(RequestNo == CLEAR_FEATURE) {
Result = Standard_ClearFeature();
}
/* SET FEATURE for EndPoint*/
else if(RequestNo == SET_FEATURE) {
Result = Standard_SetEndPointFeature();
}
}
else {
Result = USB_UNSUPPORT;
}

if(Result != USB_SUCCESS) {
Result = (*pProperty->Class_NoData_Setup)(RequestNo);
if(Result == USB_NOT_READY) {
ControlState = PAUSE;
goto exit_NoData_Setup0;
}
}

if(Result != USB_SUCCESS) {
ControlState = STALLED;
goto exit_NoData_Setup0;
}

ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */

USB_StatusIn()
;

exit_NoData_Setup0: pInformation->ControlState = ControlState;
return;
}

/*******************************************************************************
 * Function Name  : Data_Setup0.
 * Description    : Proceed the processing of setup request with data stage.
 * Input          : None.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void Data_Setup0(void)
{
uint8_t *(*CopyRoutine)(uint16_t);
RESULT Result;
uint32_t Request_No = pInformation->USBbRequest;

uint32_t Related_Endpoint, Reserved;
uint32_t wOffset, Status;

CopyRoutine = NULL;
wOffset = 0;

/*GET DESCRIPTOR*/
if(Request_No == GET_DESCRIPTOR) {
if(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) {
uint8_t wValue1 = pInformation->USBwValue1;
if(wValue1 == DEVICE_DESCRIPTOR) {
CopyRoutine = pProperty->GetDeviceDescriptor;
}
else if(wValue1 == CONFIG_DESCRIPTOR) {
CopyRoutine = pProperty->GetConfigDescriptor;
}
else if(wValue1 == STRING_DESCRIPTOR) {
CopyRoutine = pProperty->GetStringDescriptor;
} /* End of GET_DESCRIPTOR */
}
}

/*GET STATUS*/
else if((Request_No == GET_STATUS) && (pInformation->USBwValue == 0)
&& (pInformation->USBwLength == 0x0002) && (pInformation->USBwIndex1 == 0)) {
/* GET STATUS for Device*/
if((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
&& (pInformation->USBwIndex == 0)) {
CopyRoutine = Standard_GetStatus;
}

/* GET STATUS for Interface*/
else if(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) {
if(((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0)
== USB_SUCCESS) && (pInformation->Current_Configuration != 0)) {
CopyRoutine = Standard_GetStatus;
}
}

/* GET STATUS for EndPoint*/
else if(Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) {
Related_Endpoint = (pInformation->USBwIndex0 & 0x0f);
Reserved = pInformation->USBwIndex0 & 0x70;

if(ValBit(pInformation->USBwIndex0, 7)) {
/*Get Status of endpoint & stall the request if the related_ENdpoint
 is Disabled*/
Status = _GetEPTxStatus(Related_Endpoint);
}
else {
Status = _GetEPRxStatus(Related_Endpoint);
}

if((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0)
&& (Status != 0)) {
CopyRoutine = Standard_GetStatus;
}
}

}

/*GET CONFIGURATION*/
else if(Request_No == GET_CONFIGURATION) {
if(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) {
CopyRoutine = Standard_GetConfiguration;
}
}
/*GET INTERFACE*/
else if(Request_No == GET_INTERFACE) {
if((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
&& (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0)
&& (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001)
&& ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0)
== USB_SUCCESS)) {
CopyRoutine = Standard_GetInterface;
}

}

if(CopyRoutine) {
pInformation->Ctrl_Info.Usb_wOffset = wOffset;
pInformation->Ctrl_Info.CopyData = CopyRoutine;
/* sb in the original the cast to word was directly */
/* now the cast is made step by step */
(*CopyRoutine)(0);
Result = USB_SUCCESS;
}
else {
Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
if(Result == USB_NOT_READY) {
pInformation->ControlState = PAUSE;
return;
}
}

if(pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) {
/* Data is not ready, wait it */
pInformation->ControlState = PAUSE;
return;
}
if((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0)) {
/* Unsupported request */
pInformation->ControlState = STALLED;
return;
}

if(ValBit(pInformation->USBbmRequestType, 7)) {
/* Device ==> Host */
__IO uint32_t
wLength = pInformation->USBwLength;

/* Restrict the data length to be the one host asks for */
if(pInformation->Ctrl_Info.Usb_wLength > wLength) {
pInformation->Ctrl_Info.Usb_wLength = wLength;
}

else if(pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength) {
if(pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) {
Data_Mul_MaxPacketSize = false;
}
else if((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize)
== 0) {
Data_Mul_MaxPacketSize = true;
}
}

pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;
DataStageIn();
}
else {
pInformation->ControlState = OUT_DATA;
vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */
}

return;
}

/*******************************************************************************
 * Function Name  : Setup0_Process
 * Description    : Get the device request data and dispatch to individual process.
 * Input          : None.
 * Output         : None.
 * Return         : Post0_Process.
 *******************************************************************************/
uint8_t Setup0_Process(void)
{

union {
uint8_t* b;
uint16_t* w;
} pBuf;
uint16_t offset = 1;

pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */

if(pInformation->ControlState != PAUSE) {
pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */
pInformation->USBbRequest = *pBuf.b++; /* bRequest */
pBuf.w += offset; /* word not accessed because of 32 bits addressing */
pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */
pBuf.w += offset; /* word not accessed because of 32 bits addressing */
pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */
pBuf.w += offset; /* word not accessed because of 32 bits addressing */
pInformation->USBwLength = *pBuf.w; /* wLength */
}

pInformation->ControlState = SETTING_UP;
if(pInformation->USBwLength == 0) {
/* Setup with no data stage */
NoData_Setup0();
}
else {
/* Setup with data stage */
Data_Setup0();
}
return Post0_Process();
}

/*******************************************************************************
 * Function Name  : In0_Process
 * Description    : Process the IN token on all default endpoint.
 * Input          : None.
 * Output         : None.
 * Return         : Post0_Process.
 *******************************************************************************/
uint8_t In0_Process(void)
{
uint32_t ControlState = pInformation->ControlState;

if((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) {
DataStageIn();
/* ControlState may be changed outside the function */
ControlState = pInformation->ControlState;
}

else if(ControlState == WAIT_STATUS_IN) {
if((pInformation->USBbRequest == SET_ADDRESS)
&& (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) {
SetDeviceAddress(pInformation->USBwValue0);
pUser_Standard_Requests->User_SetDeviceAddress();
}
(*pProperty->Process_Status_IN)();
ControlState = STALLED;
}

else {
ControlState = STALLED;
}

pInformation->ControlState = ControlState;

return Post0_Process();
}

/*******************************************************************************
 * Function Name  : Out0_Process
 * Description    : Process the OUT token on all default endpoint.
 * Input          : None.
 * Output         : None.
 * Return         : Post0_Process.
 *******************************************************************************/
uint8_t Out0_Process(void)
{
uint32_t ControlState = pInformation->ControlState;

if((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) {
/* host aborts the transfer before finish */
ControlState = STALLED;
}
else if((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA)) {
DataStageOut();
ControlState = pInformation->ControlState; /* may be changed outside the function */
}

else if(ControlState == WAIT_STATUS_OUT) {
(*pProperty->Process_Status_OUT)();
ControlState = STALLED;
}

/* Unexpect state, STALL the endpoint */
else {
ControlState = STALLED;
}

pInformation->ControlState = ControlState;

return Post0_Process();
}

/*******************************************************************************
 * Function Name  : Post0_Process
 * Description    : Stall the Endpoint 0 in case of error.
 * Input          : None.
 * Output         : None.
 * Return         : - 0 if the control State is in PAUSE
 *                  - 1 if not.
 *******************************************************************************/
uint8_t Post0_Process(void)
{

SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);

if(pInformation->ControlState == STALLED) {
vSetEPRxStatus(EP_RX_STALL);
vSetEPTxStatus(EP_TX_STALL);
}

return (pInformation->ControlState == PAUSE);
}

/*******************************************************************************
 * Function Name  : SetDeviceAddress.
 * Description    : Set the device and all the used Endpoints addresses.
 * Input          : - Val: device address.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void SetDeviceAddress(uint8_t Val)
{
uint32_t i;
uint32_t nEP = Device_Table.Total_Endpoint;

/* set address in every used endpoint */
for(i = 0; i < nEP; i++) {
_SetEPAddress((uint8_t)i, (uint8_t)i);
} /* for */
_SetDADDR(Val | DADDR_EF); /* set device address and enable function */
}

/*******************************************************************************
 * Function Name  : NOP_Process
 * Description    : No operation function.
 * Input          : None.
 * Output         : None.
 * Return         : None.
 *******************************************************************************/
void NOP_Process(void)
{
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
